
#include <cstdio>
#include <BFile>
#include <BDate>
#include <BTime>
#include <BFont>
#include <BStyle>
#include <BCursor>

#include <BSpring>
#include <BReadWrite>
#include <BListItem>
#include <BSystem>
#include <BApplication>
#include "member_BFileDialog.h"
#include "member_BObject.h"

using namespace BWE;

bool EntryTableWidget::sortColumn(int column)
{
	if (!this->columnHeaderShown())
		return false;
	if (column >= this->columnCount())
		return false;
	if (column < 0)
	{
		for (int i = 0; i < this->columnCount(); i++)
		{
			if (this->columnSortable(i))
			{
				column = i;
				break;
			}
		}
	}
	if (column < 0)
		return false;
	int mode = this->columnSortMode(column);
	for (int row = 0; row < this->rowCount(); row++)
	{
		BTableItem *item = this->item(row, column);
		if (!item)
			continue;
		if (object_member(item)->name != item->text())
		{
			object_member(item)->name = item->text();
			object_member(item)->name.lower();
		}
	}
	int folderCount = 0;
	for (int row = 0; row < this->rowCount(); row++)
	{
		int select = row;
		BTableItem *target = this->item(row, column);
		if (!target)
			continue;
		BEntry *entry = this->item(row, 0)->asset();
		if (folderFirst && entry->attrib() & Attrib_Folder)
		{
			folderCount++;
			continue;
		}
		for (int r = row + 1; r < this->rowCount(); r++)
		{
			BTableItem *item = this->item(r, column);
			if (!item)
				continue;
			BEntry *entry = this->item(r, 0)->asset();
			if (folderFirst && entry->attrib() & Attrib_Folder)
			{
				target = item;
				select = r;
				break;
			}
			if (mode < 0 && target->name() > item->name())
			{
				target = item;
				select = r;
			}
			if (mode > 0 && target->name() < item->name())
			{
				target = item;
				select = r;
			}
		}
		if (select != row)
		{
			this->moveRow(select, row);
		}
	}
	for (int row = 0; row < folderCount; row++)
	{
		int select = row;
		BTableItem *target = this->item(row, column);
		if (!target)
			continue;
		for (int r = row + 1; r < folderCount; r++)
		{
			BTableItem *item = this->item(r, 0);
			if (!item)
				continue;
			if (mode < 0 && target->name() > item->name())
			{
				target = item;
				select = r;
			}
			if (mode > 0 && target->name() < item->name())
			{
				target = item;
				select = r;
			}
		}
		if (select != row)
		{
			this->moveRow(select, row);
		}
	}
	for (int row = 0; row < this->rowCount(); row++)
	{
		this->setRowLabel(row, row);
	}
	return true;
}

member_BFileDialog::member_BFileDialog(BFileDialog *fileDialog)
{
	boss = fileDialog;
	dirtyStyle = false;
	lineEdited = false;
	attribFilter = Attrib_All;
	selectMultiple = true;
	pathIndex = 0;

	topLayout = new BHBoxLayout("top");
	topLayout->setSpacing(3);
	{
		prevButton = new BButton(Graph_Arrow_Left_Fill);
		prevButton->setName("prev");
		prevButton->setForm(Form_IconAlone);

		nextButton = new BButton(Graph_Arrow_Right_Fill);
		nextButton->setName("next");
		nextButton->setForm(Form_IconAlone);

		aboveButton = new BButton(Graph_Arrow_Up_Fill);
		aboveButton->setName("above");
		aboveButton->setForm(Form_IconAlone);

		pathComboBox = new BComboBox();
		pathComboBox->setEditable(true);
		pathComboBox->setName("path");

		viewComboBox = new BComboBox();
		viewComboBox->setName("view");
		viewComboBox->setArrowVisible(false);
		viewComboBox->addItem("info details", 0);
		viewComboBox->addItem("info concise", 1);
		viewComboBox->addItem("icon small", 36);
		viewComboBox->addItem("icon middle", 64);
		viewComboBox->addItem("icon biggest", 128);
		viewComboBox->setValue(0);

		topLayout->addWidget(prevButton);
		topLayout->addWidget(nextButton);
		topLayout->addWidget(aboveButton);
		topLayout->addWidget(pathComboBox, 100);
		topLayout->addWidget(viewComboBox, 0);
	}

	splitLayout = new BHBoxLayout();
	splitLayout->setSplitable(true);
	splitLayout->setSpacing(6);
	{
		BVBoxLayout *indexesLayout = new BVBoxLayout();
		{
			listWidget = new BListWidget();
			listWidget->setName("list");
			listWidget->setSelectMode(Select_Single);
			listWidget->setScrollHint(ScrollHint_None);

			treeWidget = new BTreeWidget();
			treeWidget->setName("tree");
			treeWidget->setSelectMode(Select_Single);

			indexesLayout->addWidget(listWidget, 0);
			indexesLayout->addWidget(treeWidget);
		}

		tableWidget = new EntryTableWidget();
		tableWidget->setName("table");
		tableWidget->setSelectMode(Select_Multiple | Select_Rows);
		tableWidget->setColumnSortMode(0, 1);

		splitLayout->addLayout(indexesLayout, 1);
		splitLayout->addWidget(tableWidget, 3);
	}

	BVBoxLayout *layout = new BVBoxLayout(boss);
	layout->setSpacing(3);
	layout->addLayout(topLayout, 0);
	layout->addLayout(splitLayout);

	BVBoxLayout *bottomLayout = new BVBoxLayout(boss, Part_Bottom);
	{
		BHBoxLayout *nameLayout = new BHBoxLayout();
		nameLayout->setMargin(2);
		nameLayout->setSpacing(3);
		{
			BLabel *nameLabel = new BLabel("name");
			nameLabel->setAlign(Align_Center);

			nameEdit = new BLineEdit();

			filterComboBox = new BComboBox();
			filterComboBox->setMaxWidth(200);

			nameLayout->addSpring(3);
			nameLayout->addWidget(nameLabel, 1);
			nameLayout->addWidget(nameEdit, 10);
			nameLayout->addWidget(filterComboBox, 1);
		}

		BHBoxLayout *buttonLayout = new BHBoxLayout();
		buttonLayout->setMargin(2);
		buttonLayout->setSpacing(3);
		{
			okButton = new BButton("Ok");
			okButton->setName("ok");
			okButton->setMinSize(BSize(100, 0));

			cancleButton = new BButton("Cancel");
			cancleButton->setName("cancel");
			cancleButton->setMinSize(BSize(100, 0));

			buttonLayout->addSpring();
			buttonLayout->addWidget(okButton);
			buttonLayout->addWidget(cancleButton);
		}
		bottomLayout->addLayout(nameLayout);
		bottomLayout->addLayout(buttonLayout);
	}

	connect(prevButton, Signal_Clicked, &member_BFileDialog::slotBackButtonClicked);
	connect(nextButton, Signal_Clicked, &member_BFileDialog::slotFrontButtonClicked);
	connect(aboveButton, Signal_Clicked, &member_BFileDialog::slotAboveButtonClicked);
	connect(pathComboBox, Signal_CurrentChanged, &member_BFileDialog::slotPathCurrentChanged);
	connect(pathComboBox, Signal_EditFinished, &member_BFileDialog::slotPathEditFinished);
	connect(viewComboBox, Signal_ValueChanged, &member_BFileDialog::slotViewValueChanged);

	connect(listWidget, Signal_ItemClicked, &member_BFileDialog::slotListItemClicked);

	connect(treeWidget, Signal_ItemClicked, &member_BFileDialog::slotTreeItemClicked);
	connect(treeWidget, Signal_ItemDoubleClicked, &member_BFileDialog::slotTreeItemDoubleClicked);
	connect(treeWidget, Signal_Freshed, &member_BFileDialog::slotScrollAreaFreshed);

	connect(tableWidget, Signal_Framed, &member_BFileDialog::slotTableWidgetFramed);
	connect(tableWidget, Signal_Resized, &member_BFileDialog::slotTableWidgetResized);
	connect(tableWidget, Signal_Freshed, &member_BFileDialog::slotScrollAreaFreshed);
	connect(tableWidget, Signal_ItemClicked, &member_BFileDialog::slotTableItemClicked);
	connect(tableWidget, Signal_ItemHovered, &member_BFileDialog::slotTableItemHovered);
	connect(tableWidget, Signal_ItemDoubleClicked, &member_BFileDialog::slotTableItemDoubleClicked);
	connect(tableWidget, Signal_SelectionChanged, &member_BFileDialog::slotTableWidgetSelectionChanged);

	connect(nameEdit, Signal_TextEdited, &member_BFileDialog::slotNameEdited);
	connect(filterComboBox, Signal_CurrentChanged, &member_BFileDialog::slotNameFilterChanged);
	connect(okButton, Signal_Clicked, &member_BFileDialog::slotOkClicked);
	connect(cancleButton, Signal_Clicked, &member_BFileDialog::slotCancleClicked);

	resetDisks();
}
member_BFileDialog::~member_BFileDialog()
{
}

const char *member_BFileDialog::typeName(BEntry *entry)
{
	Attrib attrib = entry->attrib();
	if (attrib & Attrib_Folder)
		return "folder";
	if (attrib & Attrib_Link)
		return "link";
	if (attrib & Attrib_Pipe)
		return "pipe";
	if (attrib & Attrib_Block)
		return "block";
	if (attrib & Attrib_Char)
		return "char";
	if (attrib & Attrib_Socket)
		return "socket";
	if (attrib & Attrib_File)
	{
		return entry->name().ext();
	}
	return "*";
}
BIcon *member_BFileDialog::iconOf(BObject *object)
{
	const BStyle *style = boss->realStyle();
	BIcon *icon = 0;
	if (style)
	{
		if (BDisk *disk = dynamic_cast<BDisk *>(object))
		{
			icon = BSystem::EntryIcon(disk->name());
			if (icon == 0)
			{
				switch (disk->type())
				{
				case BDisk::Root:
					icon = style->icon("disk-root");
					break;
				case BDisk::Removable:
					icon = style->icon("disk-usb");
					break;
				case BDisk::Remote:
					icon = style->icon("disk-cloud");
					break;
				case BDisk::CDRom:
					icon = style->icon("disk-cdrom");
					break;
				case BDisk::Symbol:
					icon = style->icon("disk-symbol");
					break;
				default:
					icon = style->icon("disk");
					break;
				}
			}
		}
		if (!icon)
		{
			if (BEntry *entry = dynamic_cast<BEntry *>(object))
			{
				if (entry->attrib() & Attrib_Folder)
					icon = style->icon("folder");
				else if (entry->attrib() & Attrib_Link)
					icon = style->icon("link");
				else
				{
					BString ext("file-");
					ext << object->name().ext();
					ext.lower();
					icon = style->icon(ext);
				}
				if (!icon)
				{
					icon = BSystem::EntryIcon(entry->path());
				}
			}
		}
	}
	return icon;
}
BListItem *member_BFileDialog::symbolItem(const BString &path)
{
	for (int i = 0; i < listWidget->itemCount(); i++)
	{
		BListItem *item = listWidget->item(i);
		BDisk *disk = item->asset();
		if (disk && disk->path() == path)
		{
			return item;
		}
	}
	return 0;
}
bool member_BFileDialog::checkImage(EntryInfo &info) const
{
	if (info.typeStr == "png")
		return true;
	if (info.typeStr == "jpg" || info.typeStr == "jpeg")
		return true;
	if (info.typeStr == "tif" || info.typeStr == "tiff")
		return true;
	if (info.typeStr == "bmp")
		return true;
	if (info.typeStr == "gif")
		return true;
	if (info.typeStr == "svg")
		return true;
	int pos = imageExts.find(info.typeStr);
	return pos < imageExts.size();
}

void member_BFileDialog::resetDisks()
{
	for (int i = 0; i < BSystem::GetDiskCount(); i++)
	{
		BDisk *disk = BSystem::GetDisk(i);
		BString name = disk->name();
		name.remove("\\");
		if (disk->type() == BDisk::Symbol)
		{
			BListItem *symbolItem = listWidget->addItem(name);
			symbolItem->setIcon(iconOf(disk));
			symbolItem->setAsset(disk);
		}
		else
		{
			BTreeItem *item = treeWidget->addItem(name);
			item->setIcon(iconOf(disk));
			item->setAsset(disk);
		}
	}
	listWidget->setVisible(listWidget->itemCount());
}
void member_BFileDialog::freshListItems()
{
	const BStyle *style = boss->realStyle();
	for (int i = 0; i < listWidget->itemCount(); i++)
	{
		BListItem *item = listWidget->item(i);
		BObject *object = item->asset();
		item->setIcon(iconOf(object));
	}
}
void member_BFileDialog::freshTreeItem(BTreeItem *item)
{
	if (BObject *object = item->asset())
	{
		BIcon *icon = iconOf(object);
		item->setIcon(icon);
		for (int i = 0; i < item->childCount(); i++)
		{
			BTreeItem *child = item->child(i);
			freshTreeItem(child);
		}
	}
}
void member_BFileDialog::freshTableItems()
{
	for (int r = 0; r < tableWidget->rowCount(); r++)
	{
		for (int c = 0; c < tableWidget->columnCount(); c++)
		{
			if (BTableItem *item = tableWidget->item(r, c))
			{
				BEntry *entry = item->asset();
				if (entry && !item->image())
				{
					BIcon *icon = iconOf(entry);
					item->setIcon(icon);
				}
			}
		}
	}
	const BStyle *style = boss->realStyle();
	for (int i = 0; i < entryInfos.size(); i++)
	{
		EntryInfo &info = entryInfos[i];
		style->translate(info.typeStr, info.t_typeStr);
	}
}
void member_BFileDialog::freshBackFrontButton()
{
	if (pathIndex < 0)
		pathIndex = 0;
	if (pathIndex > pathRecords.size())
		pathIndex = pathRecords.size();
	const BString &path = pathComboBox->text();
	prevButton->setEnabled(pathIndex > 0);
	nextButton->setEnabled(pathIndex < pathRecords.size() - 1);
}
void member_BFileDialog::arrangeTableItems()
{
	if (itemEdit)
	{
		itemEdit->setAsset(BValue());
		itemEdit->hide();
	}

	int iconSize = viewComboBox->value();
	if (iconSize == 0)
	{
		tableItems.clear();
		tableWidget->clearSelection();
		if (selectMultiple)
			tableWidget->setSelectMode(Select_Multiple | Select_Rows);
		else
			tableWidget->setSelectMode(Select_Rows);
		tableWidget->setRowSpacing(2);
		tableWidget->setColumnHeaderShown(true);
		tableWidget->setRowHeaderShown(true);
		tableWidget->setHorizontalScrollHint(ScrollHint_Floating);
		tableWidget->setColumnCount(4);
		tableWidget->setColumnLabel(0, "Name");
		tableWidget->setColumnLabel(1, "Type");
		tableWidget->setColumnLabel(2, "Date");
		tableWidget->setColumnLabel(3, "Size");
		tableWidget->setColumnSortable(0, true);
		tableWidget->setColumnSortable(1, true);
		tableWidget->setColumnSortable(2, true);
		tableWidget->setColumnSortable(3, true);
		tableWidget->setColumnWidth(0, 200);
		tableWidget->setRowCount(entryInfos.size());
		for (int i = 0; i < entryInfos.size(); i++)
		{
			tableWidget->setRowLabel(i, i);
			EntryInfo &info = entryInfos[i];
			BTableItem *item = tableWidget->item(i, 0);
			if (!item)
			{
				item = new BTableItem();
				tableWidget->setItem(i, 0, item);
			}
			item->setIcon(0);
			item->setImage(0);
			item->setText(info.entry->name());
			item->setForm(Form_IconText);
			item->setAlign(Align_LeftCenter);
			item->setAsset(info.entry);
			item->setIconSize(0);
			item->setLineFeed(false);

			BTableItem *typeItem = tableWidget->item(i, 1);
			if (!typeItem)
			{
				typeItem = new BTableItem();
				tableWidget->setItem(i, 1, typeItem);
			}
			typeItem->setIcon(0);
			typeItem->setImage(0);
			if (info.t_typeStr.size())
				typeItem->setText(info.t_typeStr);
			else
				typeItem->setText(info.typeStr);
			typeItem->setForm(Form_IconText);
			typeItem->setAlign(Align_None);
			typeItem->setAsset(0);
			typeItem->setIconSize(0);

			BTableItem *timeItem = tableWidget->item(i, 2);
			if (!timeItem)
			{
				timeItem = new BTableItem();
				tableWidget->setItem(i, 2, timeItem);
			}
			timeItem->setIcon(0);
			timeItem->setImage(0);
			timeItem->setText(info.timeStr);
			timeItem->setAsset(0);
			timeItem->setIconSize(0);
			timeItem->setForm(Form_IconText);
			timeItem->setAlign(Align_None);

			BTableItem *sizeItem = tableWidget->item(i, 3);
			if (!sizeItem)
			{
				sizeItem = new BTableItem();
				tableWidget->setItem(i, 3, sizeItem);
			}
			sizeItem->setIcon(0);
			sizeItem->setImage(0);
			sizeItem->setText(info.sizeStr);
			sizeItem->setAlign(Align_Right);
			sizeItem->setAsset(0);
			sizeItem->setIconSize(0);
			sizeItem->setForm(Form_IconText);
		}
		tableWidget->setColumnPolicy(Policy_Preferred | Policy_Dynamic);
		tableWidget->setRowPolicy(Policy_Preferred);
		freshTableItems();
		tableWidget->sortColumn();
		tableWidget->scrollToItem(0);
		return;
	}
	if (iconSize == 1)
	{
		return;
	}
	tableItems.resize(entryInfos.size());
	for (int i = 0; i < entryInfos.size(); i++)
	{
		EntryInfo &info = entryInfos[i];
		BTableItem *item = new BTableItem(info.entry->name());
		item->setForm(Form_TextUnderIcon);
		item->setAlign(Align_TopCenter);
		item->setIconSize(iconSize);
		item->setImage(info.image);
		item->setAsset(info.entry);
		item->setLineFeed(true);
		tableItems[i] = item;
	}

	int columnCount = tableWidget->centerSize().width() / (iconSize + 20);
	tableWidget->setRowSpacing(10);
	tableWidget->setColumnCount(columnCount);
	tableWidget->setColumnHeaderShown(false);
	tableWidget->setRowHeaderShown(false);
	tableWidget->setHorizontalScrollHint(ScrollHint_None);
	if (selectMultiple)
		tableWidget->setSelectMode(Select_Multiple);
	else
		tableWidget->setSelectMode(Select_Single);
	tableWidget->clearItems();
	for (int i = 0; i < tableItems.size(); i++)
	{
		BTableItem *item = tableItems[i];
		tableWidget->insertItem(item);
	}
	tableWidget->setColumnPolicy(Policy_Fixed);
	tableWidget->setRowPolicy(Policy_Preferred);
	tableWidget->setColumnWidth(iconSize + 10);
	freshTableItems();
	tableWidget->scrollToItem(0);
}

void member_BFileDialog::openFolder(const BString &path)
{
	const char *cstr = path.cstr();
	BString fullPath = BFolder::AbsolutePath(path);
	BStringArray namelst = fullPath.split('/');
#ifdef linux
	namelst.replace("", "/");
#endif
	BTreeItem *item = treeWidget->itemOfText(namelst.first());
	namelst.remove(0);
	while (item && namelst.size())
	{
		if (item->childCount() == 0)
		{
			BFolder folder(item->path());
			if (folder.open())
			{
				for (int i = 0; i < folder.entryCount(); i++)
				{
					BEntry *entry = folder.entry(i);
					if (entry->attrib() & Attrib_Folder)
					{
						const BString &name = entry->name();
						BTreeItem *child = new BTreeItem(name);
						child->setAsset(entry);
						child->setIcon(iconOf(entry));
						item->addChild(child);
					}
				}
			}
		}
		treeWidget->expand(item);
		item = item->child(namelst.first());
		namelst.remove(0);
	}
	if (item)
	{
		item->setSelected(true);
		if (BListItem *symitem = symbolItem(path))
			listWidget->setItemSelected(symitem, true);
		else
			listWidget->clearSelection();
		if (pathRecords.size() == 16)
			pathRecords.remove(0);
		if (pathRecords.last() != fullPath)
		{
			pathRecords.append(fullPath);
		}
		pathIndex = pathRecords.size() - 1;
		freshBackFrontButton();
		BComboItem *comboItem = pathComboBox->itemOfText(fullPath);
		if (comboItem)
			pathComboBox->moveItem(comboItem, 0);
		else
			comboItem = pathComboBox->insertItem(0, item->icon(), fullPath);
		pathComboBox->setCurrent(comboItem);
	}
	fileNames.clear();
}
void member_BFileDialog::freshFolder(const BString &path)
{
	if (BTreeItem *item = treeWidget->locate(path))
	{
		item->clearChildren();
		BFolder folder(item->path());
		if (folder.open())
		{
			for (int i = 0; i < folder.entryCount(); i++)
			{
				BEntry *entry = folder.entry(i);
				if (entry->attrib() & Attrib_Folder)
				{
					const BString &name = entry->name();
					BTreeItem *child = new BTreeItem(name);
					child->setAsset(entry);
					child->setIcon(iconOf(entry));
					item->addChild(child);
				}
			}
		}
		if (freshEntryInfos(path))
		{
			freshBackFrontButton();
			selectEntries();
		}
	}
}
bool member_BFileDialog::freshEntryInfos(const BString &path)
{
	BFolderHolder folder = new BFolder(path, Attrib_All);
	if (folder->open())
	{
		const BStringArray &extsFilter = filterComboBox->value();
		BTreeItem *item = treeWidget->locate(path);
		treeWidget->setItemSelected(item);
		entryInfos.reset();
		BString ext;
		for (int i = 0; i < folder->entryCount(); i++)
		{
			BEntry *entry = folder->entry(i);
			Attrib attrib = entry->attrib();
			if (attrib & Attrib_File)
			{
				ext.reset();
				ext.append(entry->name().ext());
				ext.lower();
				if (extsFilter.size() && !extsFilter.contain(ext))
					continue;
			}

			EntryInfo &info = entryInfos.append();
			info.entry = entry;
			info.typeStr = this->typeName(entry);

			const BDate &date = entry->date();
			const BTime &time = entry->time();
			info.timeStr << date.year() << '-' << date.month() << '-' << date.day() << ' ' << time.hour() << ':' << time.minute() << ':' << time.second();

			if (attrib & Attrib_Folder)
				continue;
			if (attrib & Attrib_Link)
				continue;
			BLong numB = entry->size();
			if (numB < 1024)
			{
				info.sizeStr << numB << "B";
				continue;
			}
			BLong numKB = numB / 1024;
			if (numKB < 1024)
			{
				if (numB % 1024)
					numKB++;
				info.sizeStr << numKB << "KB";
				continue;
			}
			BLong numMB = numKB / 1024;
			if (numMB < 1024)
			{
				if (numKB % 1024)
					numMB++;
				info.sizeStr << numMB << "MB";
				continue;
			}
			double numGB = numMB / 1024.0;
			info.sizeStr.append(numGB, 3);
			info.sizeStr << "GB";
		}
		arrangeTableItems();
		return true;
	}
	return false;
}
void member_BFileDialog::selectEntries()
{
	BString text;
	BString ext;
	if (tableWidget->selectedItemCount())
	{
		const BStringArray &extsFilter = filterComboBox->value();
		for (int i = 0; i < tableWidget->selectedItemCount(); i++)
		{
			BTableItem *item = tableWidget->selectedItem(i);
			BEntry *entry = item->asset();
			if (!entry)
				continue;
			if (!(entry->attrib() & attribFilter))
				continue;
			if (attribFilter & Attrib_File && extsFilter.size())
			{
				ext = item->text().ext();
				ext.lower();
				if (!extsFilter.contain(ext))
					continue;
			}
			text << item->text() << ',';
		}
		text -= ",";
	}
	if (!lineEdited && attribFilter != Attrib_Folder)
	{
		if (text.empty())
			text = defaultName;
		if (text.size() && text.ext() == 0)
		{
			const BStringArray &exts = filterComboBox->value();
			if (exts.size())
			{
				text << '.' << exts.first();
			}
			while (text.replace("..", "."))
				;
		}
	}
	nameEdit->setText(text);
	okButton->setEnabled(text.size());
}

void member_BFileDialog::slotBackButtonClicked()
{
	pathIndex--;
	const BString &path = pathRecords(pathIndex);
	pathComboBox->setCurrentText(path);
	freshBackFrontButton();
}
void member_BFileDialog::slotFrontButtonClicked()
{
	pathIndex++;
	const BString &path = pathRecords(pathIndex);
	pathComboBox->setCurrentText(path);
	freshBackFrontButton();
}
void member_BFileDialog::slotAboveButtonClicked()
{
	BString text = pathComboBox->text();
	BString abovePath = text.path();
	openFolder(abovePath);
}

void member_BFileDialog::slotPathCurrentChanged(BObject *object, const BValue &value)
{
	const BString &path = pathComboBox->text();
	if (freshEntryInfos(path))
	{
		freshBackFrontButton();
		selectEntries();
	}
}
void member_BFileDialog::slotPathEditFinished(BObject *object, const BValue &value)
{
	const BString &absolutePath = value;
	openFolder(absolutePath);
}
void member_BFileDialog::slotViewValueChanged(BObject *object, const BValue &value)
{
	arrangeTableItems();
}
void member_BFileDialog::slotListItemClicked(BObject *object, const BValue &value)
{
	if (BListItem *item = value)
	{
		if (BDisk *disk = item->asset())
		{
			openFolder(disk->path());
			return;
		}
		if (BEntry *entry = item->asset())
		{
			openFolder(entry->path());
			return;
		}
	}
}
void member_BFileDialog::slotTreeItemClicked(BObject *object, const BValue &value)
{
	BTreeItem *item = value;
	if (!item)
		return;
	BString path = item->path();
	path.replace("//", "/");
	openFolder(path);
	if (itemEdit)
	{
		if (itemEdit->asset() != value)
		{
			itemEdit->setAsset(value);
			itemEdit->setPos(BCursor::GetPos());
		}
		else
		{
			bool editing = (itemEdit->pos() - BCursor::GetPos()).length2() > 5;
			if (item && editing)
			{
				BRect area = item->textArea();
				BSize ssize = itemEdit->shellSize();
				BRect rect = area + ssize;
				rect.right() += area.width() / 2;
				rect -= BPoint(ssize.width() / 2, ssize.height() / 2);
				if (rect.right() >= treeWidget->centerRect().right())
					rect.right() = treeWidget->centerRect().right() - 1;
				itemEdit->setParent(treeWidget);
				itemEdit->setRect(rect);
				itemEdit->setText(item->text());
				itemEdit->popup();
			}
		}
	}
}
void member_BFileDialog::slotTreeItemDoubleClicked(BObject *object, const BValue &value)
{
	BTreeItem *item = value;
	if (item)
	{
		if (item->expanded())
			treeWidget->shrink(item);
		else
			treeWidget->expand(item);
	}
}

void member_BFileDialog::slotTableWidgetFramed(BObject *object, const BValue &value)
{
	int iconSize = viewComboBox->value();
	if (iconSize < 10)
		return;
	BRect crect = tableWidget->centerRect();
	BPoint offset = tableWidget->offset();
	for (int r = 0; r < tableWidget->rowCount(); r++)
	{
		BRect rect = tableWidget->rowRect(r);
		if (rect.bottom() < crect.top())
			continue;
		if (rect.top() > crect.bottom())
			continue;
		for (int c = 0; c < tableWidget->columnCount(); c++)
		{
			BTableItem *item = tableWidget->item(r, c);
			if (!item || item->image())
				continue;
			BEntry *entry = item->asset();
			int index = entryInfos.find(entry);
			EntryInfo &info = entryInfos[index];
			if (!info.ready && checkImage(info))
			{
				BObject* img = ReadFile(entry->path());
				info.image = dynamic_cast<BImage*>(img);
				item->setImage(info.image);
				if (info.image)
					item->setIcon(0);
				info.ready = true;
				break;
			}
		}
	}
}
void member_BFileDialog::slotTableWidgetResized(BObject *object, const BValue &value)
{
	int iconSize = viewComboBox->value();
	if (iconSize < 10)
		return;
	int columnCount = tableWidget->centerSize().width() / (iconSize + 20);
	if (tableWidget->columnCount() != columnCount)
	{
		tableWidget->clearItems();
		tableWidget->setColumnCount(columnCount);
		for (int i = 0; i < tableItems.size(); i++)
		{
			BTableItem *item = tableItems[i];
			tableWidget->insertItem(item);
		}
		tableWidget->setColumnPolicy(Policy_Fixed);
		tableWidget->setRowPolicy(Policy_Preferred);
		tableWidget->setColumnWidth(iconSize + 10);
		freshTableItems();
		tableWidget->scrollToItem(0);
	}
}
void member_BFileDialog::slotTableItemClicked(BObject *object, const BValue &value)
{
	if (itemEdit)
	{
		BTableItem *item = value;
		if (itemEdit->asset() != value)
		{
			itemEdit->setAsset(value);
			itemEdit->setPos(BCursor::GetPos());
		}
		else
		{
			bool editing = (itemEdit->pos() - BCursor::GetPos()).length2() > 5;
			if (item && editing)
			{
				BRect area = item->textArea();
				BSize ssize = itemEdit->shellSize();
				BRect rect = area + ssize;
				rect -= BPoint(ssize.width() / 2, ssize.height() / 2);
				if (rect.right() >= tableWidget->centerRect().right())
					rect.right() = tableWidget->centerRect().right() - 1;
				itemEdit->setParent(tableWidget);
				itemEdit->setRect(rect);
				itemEdit->setText(item->text());
				itemEdit->popup();
			}
		}
	}
}
void member_BFileDialog::slotTableItemHovered(BObject *object, const BValue &value)
{
	BString tips;
	if (BTableItem *item = value)
	{
		BEntry *entry = item->asset();
		for (int i = 0; i < entryInfos.size(); i++)
		{
			EntryInfo &info = entryInfos[i];
			if (info.entry == entry)
			{
				tips << info.entry->name() << '\n';
				if (info.t_typeStr.size())
					tips << "type : " << info.t_typeStr << '\n';
				else
					tips << "type : " << info.typeStr << '\n';
				if (0 == (entry->attrib() & Attrib_Folder))
				{
					tips << "size : " << (BULong)entry->size() << " B\n";
				}
				tips << "time : " << info.timeStr;
				break;
			}
		}
	}
	tableWidget->setTips(tips);
}
void member_BFileDialog::slotTableItemDoubleClicked(BObject *object, const BValue &value)
{
	BTableItem *item = value;
	if (item)
	{
		BEntry *entry = (BEntry *)item->asset();
		if (entry->attrib() & Attrib_Folder)
		{
			openFolder(entry->path());
		}
		else if (entry->attrib() & Attrib_Link)
		{
			BValue value;
			if (entry->query("target", value))
			{
				const BString &path = value;
				openFolder(path);
			}
		}
		else
		{
			selectEntries();
			if (okButton->enabled())
			{
				boss->close(true);
			}
		}
	}
}
void member_BFileDialog::slotTableWidgetSelectionChanged(BObject *object, const BValue &value)
{
	selectEntries();
}

void member_BFileDialog::slotScrollAreaFreshed(BObject *object, const BValue &value)
{
	if (itemEdit && itemEdit->visible())
	{
		BSize ssize = itemEdit->shellSize();
		if (BTreeItem *item = itemEdit->asset())
		{
			BRect area = item->textArea();
			BRect rect = area + ssize;
			rect.right() += area.width() / 2;
			rect -= BPoint(ssize.width() / 2, ssize.height() / 2);
			if (rect.right() >= treeWidget->centerRect().right())
				rect.right() = treeWidget->centerRect().right() - 1;
			itemEdit->setRect(rect);
			return;
		}
		if (BTableItem *item = itemEdit->asset())
		{
			BRect area = item->textArea();
			BRect rect = area + ssize;
			rect.right() += area.width() / 2;
			rect -= BPoint(ssize.width() / 2, ssize.height() / 2);
			if (rect.right() >= tableWidget->centerRect().right())
				rect.right() = tableWidget->centerRect().right() - 1;
			itemEdit->setRect(rect);
			return;
		}
	}
}
void member_BFileDialog::slotItemEditFocused(BObject *object, const BValue &value)
{
	if (value == false)
	{
		itemEdit->setAsset(BValue());
		itemEdit->hide();
	}
}
void member_BFileDialog::slotItemEditFinished(BObject *object, const BValue &value)
{
	if (BTreeItem *item = object->asset())
	{
		if (item->text() != itemEdit->text())
		{
			BEntry *entry = item->asset();
			BTableItem *tableItem = tableWidget->itemOfText(entry->name());
			entry->rename(itemEdit->text());
			item->setText(itemEdit->text());
			if (tableItem)
			{
				tableItem->setText(itemEdit->text());
			}
		}
		return;
	}
	if (BTableItem *item = object->asset())
	{
		if (item->text() != itemEdit->text())
		{
			BEntry *entry = item->asset();
			BTreeItem *pathItem = treeWidget->selectedItem();
			BTreeItem *treeItem = pathItem->child(entry->name());
			entry->rename(itemEdit->text());
			item->setText(itemEdit->text());
			if (treeItem)
			{
				treeItem->setText(itemEdit->text());
			}
		}
		return;
	}
}
void member_BFileDialog::slotNameEdited(BObject *object, const BValue &value)
{
	const BString &text = nameEdit->text();
	okButton->setEnabled(text.size() > 0);
	lineEdited = true;
}
void member_BFileDialog::slotNameEditFinished(BObject *object, const BValue &value)
{
	okButton->setFocused(true);
}
void member_BFileDialog::slotNameFilterChanged(BObject *object, const BValue &value)
{
	const BString &path = pathComboBox->text();
	if (freshEntryInfos(path))
	{
		freshBackFrontButton();
		selectEntries();
	}
	if (BComboItem *item = value)
	{
		filterComboBox->setTips(item->text());
	}
	else
	{
		filterComboBox->setTips(BString());
	}
}

void member_BFileDialog::slotOkClicked()
{
	boss->close(true);
}
void member_BFileDialog::slotCancleClicked()
{
	boss->close();
}
